/**
 * Created by Administrator on 2017/7/2.
 */
console.log("charpter2");
console.log(1 - 0.41); //0.5900000000000001 double不能精确计算
console.log((8).toString(2));//1000 数字转其他进制输出
console.log(parseInt("1001", 2));//9 其他进制转数字


console.log("charpter3");
console.log("17" * 3); //51
console.log(NaN === NaN);//false
console.log(isNaN(NaN));//true
console.log(isNaN("haha"));//true
console.log(isNaN(""));//false
console.log(isNaN(null));//false
console.log(isNaN(undefined));//true
console.log(null === null);//true
console.log(undefined === undefined);//true
function isReallyNaN(a) { // 判断参数到底是不是NaN的最简单方法
	return a !== a;
}
console.log("object : " + {
		toString: function () {
			return "object"
		}, valueOf: function () {
			return 123;
		}
	}); //优先选择valueOf作为返回值


console.log("charpter4");
console.log(typeof null); //object
console.log(typeof undefined);//undefined
console.log(typeof NaN);//number
console.log(typeof true);//boolean
//String类和字符串还是有区别的
console.log(typeof "");//string
console.log(typeof new String());//object
console.log("123" === "123");//true
console.log(new String("123") == new String("123"));//false


console.log("charpter4");
// == 比较的原则为
console.log(null == undefined); //true 1.null,undefined 与 null,undefined比较不转型直接返回true
console.log(null == 0); //false 2. null,undefined 与 非null,undefined 比较不转型直接返回false

// 3.非null,undefined原始类型与Date比较都转为数字,Date比较特殊,优先调用toString而不是valueOf
var dateToStringFunction = Date.prototype.toString;
Date.prototype.toString = function () {
	console.log("Date.toString");
	var result = dateToStringFunction.apply(this, arguments);
	console.log(result);//Sun Jul 02 2017 18:12:42 GMT+0800 (中国标准时间)
	return result;
}
var dateValueOfFunction = Date.prototype.valueOf;
Date.prototype.valueOf = function () {
	console.log("Date.valueOf");
	var result = dateValueOfFunction.apply(this, arguments);
	console.log(result);
	return result;
}
console.log(true == new Date()); //false 因为转化成数字 new Data().toString() 结果为NaN
//clean
Date.prototype.toString = dateToStringFunction;
Date.prototype.valueOf = dateValueOfFunction;

// 4.非null,undefined原始类型与非Date比较都转为数字,优先调用valueOf
var objectToStringFunction = Object.prototype.toString;
Object.prototype.toString = function () {
	console.log("Object.toString");
	var result = objectToStringFunction.apply(this, arguments);
	console.log(result);
	return result;
}
var objectValueOfFunction = Object.prototype.valueOf;
Object.prototype.valueOf = function () {
	console.log("Object.valueOf");
	var result = objectValueOfFunction.apply(this, arguments);
	console.log(result); //Object
	return result;
}
console.log(true == new Object()); //false
//clean
Object.prototype.toString = objectToStringFunction;
Object.prototype.valueOf = objectValueOfFunction;

//5.非null,undefined原始类型与非null,undefined原始类型比较转为数字
console.log(true == "1"); //true


console.log();
console.log("charpter8");
//console.log(a); //Uncaught ReferenceError: a is not defined
console.log(this.a);//undefined

console.log();
console.log("charpter11");
(function () {
	function f() {
		var a = 1;

		function add1() {
			a++;
			console.log(a);
		}

		function add2() {
			a++;
			console.log(a);
		}

		add1(); // 2
		add2(); // 3
	}

	f();
})();


console.log();
console.log("charpter13");
(function () {
	function f() {
		var a = 1;

		function add1() {
			a++;
			console.log(a);
		}

		function add2() {
			a++;
			console.log(a);
		}
	}

	f();
	console.log(this);
})();


console.log();
console.log("charpter14");
// 以下测试说明的我的360极速的chrome内核已经支持es5了.
(function () {
	var constructor = function () {
		return null;
	};
	var f = function f() {
		return console.log(constructor());//null
	};
	f();

	var f = function () {
		return console.log(constructor());//null
	};
	f();
})();

(function () {
	var f = function g() {
	};

	console.log(f); //function g(){}
	//console.log(g);//Uncaught ReferenceError: g is not defined
})();

console.log();
console.log("charpter15");
(function () {
	function f() {
		return "global";
	}

	function test(x) {
		var g = f;
		result = [];
		if (x) {
			g = function () {
				return "local";
			}
			result.push(g());
		}
		result.push(g());
		return result;
	}

	console.log(test(false)); //["global"]
	console.log(test(true)); // ["local", "local"]
})();


var a = "global";
console.log();
console.log("charpter17");
//直接调用eval就和普通函数一样,间接调用的话只能访问全局作用域
(function () {
	var a = "outer";

	function test() {
		var a = "inner";
		console.log(eval("a")); //inner
	}

	test();

	function test2() {
		var a = "inner";
		console.log((0, eval)("a"));//global
	}

	test2();

	function test3() {
		var a = "inner";
		var f = eval;
		console.log(f("a"));//global
	}

	test3();

	function test4() {
		var a = "inner";
		console.log((eval)("a"));//inner
	}

	test4();

	function test5() {
		//var a = "inner";
		console.log(eval("a")); //outer
	}

	test5();
})();


console.log();
console.log("charpter23");
//obj 指向 arguments[0] . method指向 arguments[1]
(function () {
	function callMethod(obj, method) {
		var shift = [].shift;
		shift.call(arguments);
		shift.call(arguments);
		return obj[method].apply(obj, arguments);
	}

	var obj = {
		add: function (x, y) {
			return x + y;
		}
	}

	//callMethod(obj, "add", 17, 25); //Uncaught TypeError: Cannot read property 'apply' of undefined
})();


console.log();
console.log("charpter25");
(function () {
	function f() {
		console.log(this);
	}

	var f2 = f.bind({});
	f();//window
	f2();//object

})();

console.log();
console.log("charpter26");
(function () {
	function f(a, b, c) {
		console.log(arguments); // ["a", "b", 1, 0, Array[3]] ......value=1 index=0 array=Array[3]
		return a + b + c;
	}

	var a = [1, 2, 3];
	var b = a.map(f.bind(null, "a", "b")); //用bind简化函数调用,固定值可以直接写死.
	console.log(b); //["ab1", "ab2", "ab3"]

	//猜测bind的原理
	function bind2() {
		var arg0 = arguments;
		var me = this;
		return function () {
			var arg = [].slice.apply(arg0, [1]);
			arg.push.apply(arg, arguments) //后来发现array有个concat方法直接可以用....args.concat(arguments)
			return me.apply(arg0[0], arg);
		}
	}

	Function.prototype.bind2 = bind2;
	//bind2 实验1
	var b2 = a.map(f.bind2(null, "c", "d"));
	console.log(b2); //["cd1", "cd2", "cd3"]
	//bind2 实验2
	var fun = console.log.bind2(console, "jet: ");
	fun("hello world!"); //jet:  hello world!
	//bind2 实验3
	var fun2 = function () {
		console.log(this);
	}
	fun2.bind2(new Date())(); //Sun Jul 09 2017 16:12:55 GMT+0800 (中国标准时间)
})();


console.log();
console.log("charpter27");
var a = "global";
(function () {
	var a = "outer";

	function f(n) {
		eval(n);
	}

	function log() {
		var a = "inner";
		f("console.log(a)");
	}

	log(); //outer


	function f2() {
		console.log(a);
	}

	function log2() {
		var a = "inner";
		f2();
	}

	log2(); //outer
})();

console.log();
console.log("charpter30");
(function () {
	var a = {};
	console.log(Object.getPrototypeOf(a) === Object.prototype);//true
	console.log(Object.getPrototypeOf("") === String.prototype);//true

	function f(a, b) {
		this.a = a;
		this.b = b;
	}

	f.prototype.c = 1;
	console.log(f.toString === Function.prototype.toString);//true
	console.log(f.toString === Object.prototype.toString);//false
	console.log(f.prototype.a);//undefined 构造函数构造出来的对象的属性不再原型对象上
	//和java的原理一样,就是创建的时候对象有个指向原型的指针
	var objF = new f();
	console.log(objF.c);//1
	f.prototype.c = 2;
	console.log(objF.c);//2
	f.prototype = {};
	console.log(objF.c);//2
})();

console.log();
console.log("charpter33");
(function () {
	function f() {
		return new String("123");
	}

	console.log(new f()); //String {0: "1", 1: "2", 2: "3", length: 3, [[PrimitiveValue]]: "123"} return可以覆盖new返回的对象
})();

console.log();
console.log("charpter41");
(function () {
	function f(x) {
		this.a = x;
	}

	f.prototype.a2 = function () {

	}

	function f2(x, y) {
		f.call(this, x);
		this.b = y;
	}

	f2.prototype = Object.create(f.prototype);
	f2.prototype.b2 = function () {

	}

	var test = new f2();
	console.log(test);
	console.log(test.__proto__ === f2.prototype); // true
	console.log(f2.prototype.__proto__ === f.prototype); // true
	console.log(test.hasOwnProperty("b2")); // false
	console.log(test.hasOwnProperty("b")); // true
	console.log(test.hasOwnProperty("a")); // true 实例都是定义在对象里的
	console.log(f2.prototype.hasOwnProperty("b2")); // true
})();


console.log();
console.log("charpter43");
//利用Object.defineProperty可以添加特殊属性
(function () {
	var o = {}; // 创建一个新对象
// Example of an object property added with defineProperty with a data property descriptor
	Object.defineProperty(o, "a", {
		value: 37,
		writable: true,
		enumerable: false,
		configurable: true
	});

	var o2 = {a: 37};

	for (var i in o) {
		console.log(i); //无输出,因为不能枚举a属性
	}
	for (var i in o2) {
		console.log(i); //a
	}

	console.log({} instanceof Object);//true
	console.log({}.__proto__ === Object.prototype);//true
})();

console.log();
console.log("charpter44");
(function () {
	function f() {

	}

	f.prototype = null;
	var a = new f();
	console.log(Object.getPrototypeOf(a) === Object.prototype); // true

	var b = Object.create(null);
	console.log(Object.getPrototypeOf(b) === null); // true 利用Object.create(null);来创建空原型的对象
})();

console.log();
console.log("charpter45");
(function () {
	var a = {};
	console.log("toString" in a); //true

	for (var i in a) {
		console.log(i); //无输出,不能被遍历的属性用in还是返回true的
	}

})();


console.log();
console.log("charpter58");
(function () {
	console.log(typeof []); //object
	console.log(typeof {}); //object
	console.log([] instanceof Array); //true
	console.log(Array.isArray([])); //true
})();

console.log();
console.log("charpter61");
(function () {
	//3 1 2
	// $.ajax({
	// 	url: "/a.jsp",
	// 	success: function (data) {
	// 		for (var i = 0; i < 10000000000; i++) {
	//
	// 		}
	// 		console.log(1);
	// 	}
	// });
	// $.ajax({
	// 	url: "/b.jsp",
	// 	success: function (data) {
	// 		console.log(2);
	// 	}
	// });
	// console.log(3);
})();

console.log();
console.log("charpter62");
(function () {
	// 3 4 5 1 2
	$.ajax({
		url: "/a.jsp",
		success: function (data) {
			for (var i = 0; i < 1000000000; i++) {

			}
			console.log(1);
		}
	});
	$.ajax({
		url: "/b.jsp",
		success: function (data) {
			console.log(2);
		}
	});
	console.log(3);
	for (var i = 0; i < 3000000000; i++) {

	}
	$.ajax({
		async: false,
		url: "/a.jsp",
		success: function (data) {
			for (var i = 0; i < 1000000000; i++) {

			}
			console.log(4);
		}
	});
	console.log(5);
})();

(function () {
	// 5 1
	$.ajax({
		url: "/a.jsp",
		success: function (data) {
			console.log(1);
		}
	});
	for (var i = 0; i < 3000000000; i++) {

	}
	console.log(5);
})();

(function () {
	// 后台哪个断点先放开就输出哪个对应的值
	$.ajax({
		url: "/TestServlet",
		success: function (data) {
			console.log(1);
		}
	});
	$.ajax({
		url: "/TestServlet2",
		success: function (data) {
			console.log(2);
		}
	});
	console.log(5);
})();

(function () {
	// 在打印2之前后台就会收到请求,但是就算返回了还是先输出2再输出1
	$.ajax({
		url: "/TestServlet",
		success: function (data) {
			console.log(1);
		}
	});
	for (var i = 0; i < 3000000000; i++) {

	}
	console.log(2);
})();